# Copyright (c) 2019 Presto Labs Pte. Ltd.
# Author: leon

import ujson as json
import functools

from coin.base.book.types import TradeSide, create_market_trade_event
from coin.exchange.base.ws.handler import WebsocketHandler
from coin.exchange.coinone_v2.book_builder import BookBuilder
from coin.exchange.coinone_v2.kr_rest.product import CoinoneProduct


@functools.lru_cache(maxsize=64)
def get_product_from_trading_pair(trading_pair):
  return CoinoneProduct.FromStrNativeProduct(trading_pair)


class CoinoneHandler(WebsocketHandler):
  def on_book(self, record, queue_data, topic_data):
    data = record.data
    if not isinstance(data, dict) and not isinstance(data, list):
      data = json.loads(data.tobytes())

    product = get_product_from_trading_pair(data['trading_pair'])
    native_symbol = product.native_symbol
    if not self.is_subscribed('book', native_symbol):
      return

    bids = data['BID']
    asks = data['ASK']
    book = BookBuilder(native_symbol, book_builder_observer=self._book_builder_observer)
    book.snapshot(bids, asks)
    book.update_timestamp(record.timestamp)
    book.update_topic_id(record.topic_id)
    self._books[native_symbol] = book
    self.ready = True
    if self._feed_checker:
      self._feed_checker.on_book(product=product, book=book, timestamp=record.timestamp)
    self.publish_event('book', book.symbol, book)
    book.reset_observer()

  def on_trade(self, record, queue_data, topic_data):
    data = record.data
    if not isinstance(data, dict) and not isinstance(data, list):
      data = json.loads(data.tobytes())

    product = get_product_from_trading_pair(data['trading_pair'])
    native_symbol = product.native_symbol
    if not self.is_subscribed('trade', native_symbol):
      return

    price = float(data['price'])
    qty = float(data['volume'])
    if data['is_seller_maker'] == '1':
      assert data['is_ask'] == '1'
      side = TradeSide.TRADE_BUY_SIDE
    elif data['is_seller_maker'] == '0':
      assert data['is_ask'] == '0'
      side = TradeSide.TRADE_SELL_SIDE
    else:
      raise ValueError('Unknown side: %s', data)
    trade_event = create_market_trade_event(record.timestamp,
                                            native_symbol,
                                            price,
                                            qty,
                                            side,
                                            topic_id=record.topic_id)
    if self._feed_checker:
      self._feed_checker.on_trade(product=product,
                                  trade_event=trade_event,
                                  timestamp=record.timestamp)
    self.publish_event('trade', native_symbol, trade_event)
